
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <buf.h>
#include <event.h>
#include <log.h>

#include "client.h"
#include "command.h"
#include "server.h"
#include "setting.h"

#define MAX_LINE 998
#define MAX_SIZE 4096

extern struct setting_t g_setting;
extern struct event_t *g_event;

struct client_t g_client;
char g_line[MAX_LINE+1];
char *g_vline;

int client_init()
{
	g_client.bufin = buf_create("client in", MAX_SIZE);
	g_client.bufout = buf_create("client out", MAX_SIZE);

	g_client.lastcmd = g_client.starttime = time(NULL);

	buf_add(g_client.bufout, "* OK IMAP Proxy ready\r\n", 23);
	buf_write(g_client.bufout, STDOUT_FILENO);

	strcpy(g_client.cliaddr, "10.10.10.10"); 

	snprintf(g_client.servaddr, sizeof(g_client.servaddr), "%s", g_setting.imapd_domain);
	g_client.servport = g_setting.imapd_port;

	return 0;
}

int client_timeout()
{
	if(difftime(time(NULL), g_client.lastcmd) > g_setting.timeout) {
		buf_add(g_client.bufout, "* OK IMAP Proxy bye\r\n", 21);
		buf_write(g_client.bufout, STDOUT_FILENO);
		event_stop(g_event);
	}

	return 0;
}

int client_word(char *str, char *word, int len)
{
	char *p;

	p=strchr(str, ' ');
	if(p) {
		*p = '\0';
		g_vline = p+1;
	} else {
		g_vline = str+strlen(str);
	}

	if(strlen(str) == 0) {
		return -1;
	}

	strncpy(word, str, len);

	return 0;
}

int client_input(int fd, void *arg)
{
	int n;
	struct client_t *cli = arg;

	g_client.lastcmd = time(NULL);

	n = buf_read(cli->bufin, fd);
	if(n == 0) {
		return 0;
	}

	bzero(g_line, sizeof(g_line));
	g_vline = g_line;
	bzero(cli->cmd, sizeof(cli->cmd));
	bzero(cli->tag, sizeof(cli->tag));

	n = buf_getline(cli->bufin, g_line, MAX_LINE);
	if(n == 0) {
		return 0;
	}

	//printf("getline [%s]\n", g_line);

	client_word(g_vline, cli->tag, sizeof(cli->tag)-1);
	client_word(g_vline, cli->cmd, sizeof(cli->cmd)-1);

	if(strcasecmp(cli->cmd, "login") == 0) {
		bzero(cli->user, sizeof(cli->user));
		bzero(cli->pass, sizeof(cli->pass));
		client_word(g_vline, cli->user, sizeof(cli->user)-1);
		client_word(g_vline, cli->pass, sizeof(cli->pass)-1);

		if(strlen(cli->user) == 0 || strlen(cli->pass) == 0 ||
				strlen(g_vline) > 0) {
			cmd_bad(cli);
		} else {
			cmd_login(cli, cli->user, cli->pass);
		}
	} else if(strcasecmp(cli->cmd, "logout") == 0) {
		if(strlen(g_vline) > 0) {
			cmd_bad(cli);
		} else {
			cmd_logout(cli);
			event_stop(g_event);
		}
	} else if(strcasecmp(cli->cmd, "capability") == 0) {
		if(strlen(g_vline) > 0) {
			cmd_bad(cli);
		} else {
			cmd_capability(cli);
		}
	} else if(strcasecmp(cli->cmd, "noop") == 0) {
		if(strlen(g_vline) > 0) {
			cmd_bad(cli);
		} else {
			cmd_noop(cli);
		}
	} else if(strcasecmp(cli->cmd, "authenticate") == 0) {
		if(strlen(g_vline) > 0) {
			cmd_bad(cli);
		} else {
			cmd_authenticate(cli);
		}
	} else {
		cmd_no(cli);
	}

	buf_write(g_client.bufout, STDOUT_FILENO);

	return 0;
}

// read from client
int client_trans(int fd, void *arg)
{
	int n;

	g_client.lastcmd = time(NULL);

	n = buf_read(g_client.bufin, fd);
	if(n == -1) {
		event_stop(g_event);
	}

	LOGD("from client buf_read : %s, read from : %d", buf_data(g_client.bufout), n);

	if(n > 0) {

		event_add(g_event, g_server.fd, EVTYPE_WT, client_write, &g_client);
	}

	return n;
}

// write to server
int client_write(int fd, void *arg)
{
	int n;

	n = buf_write(g_client.bufin, fd);
	if(n == -1) {
		event_stop(g_event);
	}

    if(buf_length(g_client.bufin) == 0) {
		event_del(g_event, fd, EVTYPE_WT);
	}

	LOGD("to server write : %d", n);

	return n;
}
